package com.game.commons.database;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Savepoint;

import org.apache.log4j.Logger;

/**
 * 事物操作
 * @author 杜祥
 * @create 2013-7-1
 */
public class Transaction
{
	private final static Logger log = Logger.getLogger(Transaction.class);
	
	/**
	 * 这个事物的连接
	 */
	private Connection connection;
	
	/**
	 * 封装私有构造函数，通过{@link com.game.commons.database.DB#beginTransaction()}类应当被实例化
	 * @param con
	 * 				这个事物的连接
	 * @throws SQLException
	 * 				不能禁用自动提交模式抛出此异常
	 */
	Transaction(Connection con) throws SQLException
	{
		this.connection = con;
		connection.setAutoCommit(false);
	}
	
	/**
	 * 往事物中添加插入或更新语句,并以自动的方式执行。
	 * @param sql
	 * @throws SQLException
	 */
	public void insertUpdate(String sql) throws SQLException
	{
		insertUpdate(sql);
	}
	
	
	/**
	 * 往事物中添加插入或更新语句，iusth为null的时候以自动的方式执行SQL，否则以手动方式执行。
	 * @param sql			
	 * 						要执行的SQL语句
	 * @param iusth
	 * 						手动执行模板
	 * @throws SQLException
	 * 						无法创建PreparedStatement时抛出此异常
	 */
	public void insertUpdate(String sql, IUStH iusth) throws SQLException
	{
		PreparedStatement statement = connection.prepareStatement(sql);
		
		if(iusth != null)
		{
			iusth.handleInsertUpdate(statement);
		}
		else
		{
			statement.executeUpdate();
		}
	}
	
	/**
	 *  在当前事务中创建一个具有给定名称的保存点，并返回表示它的新 Savepoint 对象。
	 * @param name		保存点的名称
	 * @return			返回表示它的新 Savepoint 对象。
	 * @throws SQLException
	 */
	public Savepoint setSavepoint(String name) throws SQLException
	{
		return connection.setSavepoint(name);
	}
	
	
	/**
	 *  从当前事务中移除指定的 Savepoint 和后续 Savepoint 对象。
	 * @param savepoint		保存点的名称
	 * @throws SQLException
	 */
	public void releaseSavepoint(Savepoint savepoint) throws SQLException
	{
		connection.releaseSavepoint(savepoint);
	}
	
	/**
	 * 提交事物,事物提交失败时全部回滚。
	 * @throws SQLException
	 */
	public void commit() throws SQLException
	{
		commit(null);
	}
	
	
	/**
	 * 提交事物，rollBackToOnErro=null时事物失败回滚事物的所有操作，否则回滚到指定保存点处
	 * @param rollBackToOnError
	 * @throws SQLException
	 */
	public void commit(Savepoint rollBackToOnError) throws SQLException
	{
		try 
		{
			connection.commit();
		} 
		catch (SQLException e)
		{
			log.warn("事物提交出错！", e);
			try 
			{
				if(rollBackToOnError != null)
				{
					connection.rollback(rollBackToOnError);
				}
				else
				{
					connection.rollback();
				}
			}
			catch (SQLException e1) 
			{
				log.warn("事物回滚出错！", e);
			}
		}
		connection.setAutoCommit(false);
		connection.close();
	}
}
